import * as http from "http";
import { HttpComponent } from "../../../../Model/Server/Module/Http/HttpComponent";
import { ObjectSystemAttribute, FriendOf, ExpandOf, GetTypeOf, HttpHandlerAttribute, GetCustomAttributes, HttpHandlerAttrData } from "../../../../../Decorator/Decorator";
import { Awake1System } from "../../../../../Core/Module/EventSystem/IAwakeSystem";
import { DestroySystem } from "../../../../../Core/Module/EventSystem/IDestroySystem";
import { LoadSystem } from "../../../../../Core/Module/EventSystem/ILoadSystem";
import { Log } from "../../../../../Core/Module/Log/Log";
import { Scene } from "../../../../../Core/Module/Entity/Scene";
import { EventSystem } from "../../../../../Core/Module/EventSystem/EventSystem";
import { Exception } from "../../../../../Core/Object/Exception";
import { Dictionary } from "../../../../../Support/Share/Lib/Dictionary";
import { IHttpHandler } from "../../../../Model/Server/Module/Http/IHttpHandler";
import { HttpListenerContext } from "../../../../../Core/System/Server/HttpListenerContext";


/**
 * 使用 Expand 扩展方法
 * 
 * 必须作出以下申明，才能调用对象的扩展方法
 */
declare module "../../../../Model/Server/Module/Http/HttpComponent" {

    interface HttpComponent {
        Load(): void;
        Handle(context);
    }

}

@ExpandOf(HttpComponent)
export class HttpComponentSystem {

    private static Load(self: HttpComponent): void {
        self.dispatcher = new Dictionary<string, IHttpHandler>();

        const types = EventSystem.Instance.GetTypes(GetTypeOf(HttpHandlerAttribute));
        const sceneType = self.GetParent<Scene>().SceneType;
        for (let type in types) {
            let clazz = types[type];
            let attrs = GetCustomAttributes(clazz);
            if (attrs.length == 0) {
                continue;
            }
            const httpHandlerAttribute = attrs[0] as HttpHandlerAttrData;
            if (httpHandlerAttribute.SceneType != sceneType) {
                continue;
            }
            const obj = new clazz();
            const ihttpHandler = obj as IHttpHandler;
            if (ihttpHandler == null) {
                throw new Exception(`HttpHandler handler not inherit IHttpHandler class: ${GetTypeOf(obj)}`);
            }
            self.dispatcher.Add(httpHandlerAttribute.Path, ihttpHandler);
        }
    }

    private static async Handle(self: HttpComponent, context: HttpListenerContext) {
        try {
            const handler = self.dispatcher.TryGetValue(context.req.url);
            if (handler) {
                await handler.Handle(self.Domain, context);
            }
        } catch (e) {
            Log.Error(e);
        }
    }

}

@FriendOf(HttpComponent)
@ObjectSystemAttribute()
export class HttpComponentAwake1System extends Awake1System<HttpComponent, string> {

    Awake(self: HttpComponent, address: string): void {
        const param = address.split(":");
        const port = param[1];

        self.Load();
        self.Listener = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => {
            const context = new HttpListenerContext(req, res);
            self.Handle(context);
        });
        self.Listener.listen(port);
    }

}

@FriendOf(HttpComponent)
@ObjectSystemAttribute()
export class HttpComponentDestroySystem extends DestroySystem<HttpComponent> {

    Destroy(self: HttpComponent): void {
        self.Listener.close();
    }

}

@FriendOf(HttpComponent)
@ObjectSystemAttribute()
export class HttpComponentLoadSystem extends LoadSystem<HttpComponent> {

    Load(self: HttpComponent): void {
        self.Load();
    }

}